package cn.com.ejiakanghu.service;

import cn.com.ejiakanghu.core.utils.RespUtil;
import cn.com.ejiakanghu.core.vo.BaseResult;
import cn.com.ejiakanghu.web.alimini.AliMiniConfig;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeCreateRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeCreateResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.order.WxPayMwebOrderResult;
import org.apache.commons.lang.StringUtils;
import org.linlinjava.litemall.core.notify.NotifyService;
import org.linlinjava.litemall.core.notify.NotifyType;
import org.linlinjava.litemall.core.qcode.QCodeService;
import org.linlinjava.litemall.core.task.TaskService;
import org.linlinjava.litemall.core.util.DateTimeUtil;
import org.linlinjava.litemall.core.util.JacksonUtil;
import org.linlinjava.litemall.db.domain.LitemallGroupon;
import org.linlinjava.litemall.db.domain.LitemallGrouponRules;
import org.linlinjava.litemall.db.domain.LitemallOrder;
import org.linlinjava.litemall.db.service.LitemallGrouponRulesService;
import org.linlinjava.litemall.db.service.LitemallGrouponService;
import org.linlinjava.litemall.db.service.LitemallOrderService;
import org.linlinjava.litemall.db.util.GrouponConstant;
import org.linlinjava.litemall.db.util.OrderHandleOption;
import org.linlinjava.litemall.db.util.OrderUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import static cn.com.ejiakanghu.core.utils.WxResponseCode.ORDER_INVALID_OPERATION;


/**
 * @author houzb
 * @Description
 * @create 2021-04-14 13:40
 */
@Service
public class AliPayService {
    private Logger logger = LoggerFactory.getLogger(AliPayService.class);

    @Autowired
    private LitemallOrderService orderService;
    @Autowired
    private LitemallGrouponRulesService grouponRulesService;
    @Autowired
    private LitemallGrouponService grouponService;
    @Autowired
    private QCodeService qCodeService;
    @Autowired
    private NotifyService notifyService;
    @Autowired
    private TaskService taskService;

    /**
     * 微信H5支付
     *
     * @param userId
     * @param body
     * @return
     */
    @Transactional
    public BaseResult aliPay(Integer userId, String body) {
        if (userId == null) {
            return RespUtil.unlogin();
        }
        Integer orderId = JacksonUtil.parseInteger(body, "orderId");
        if (orderId == null) {
            return RespUtil.badArgument();
        }

        LitemallOrder order = orderService.findById(userId, orderId);
        if (order == null) {
            return RespUtil.badArgumentValue();
        }
        if (!order.getUserId().equals(userId)) {
            return RespUtil.badArgumentValue();
        }

        // 检测是否能够取消
        OrderHandleOption handleOption = OrderUtil.build(order);
        if (!handleOption.isPay()) {
            return RespUtil.fail(ORDER_INVALID_OPERATION, "订单不能支付");
        }

        WxPayMwebOrderResult result = null;
        try {
            String orderCode = order.getOrderSn();
            String orderName = order.getShipSn();

            // 元转成分

            //订单的额外费用，包时卡是押金费用，邮寄物品为邮寄费用
            //订单价值
            double orderPrice = order.getActualPrice().doubleValue();
            double totalPrice = orderPrice;
            if (totalPrice == 0) {//总价为0不进行支付操作
                return RespUtil.success();
            }
            String total_fee = totalPrice + "";
            //进行统一下单
            Map<String, String> resultPay = aliPayAccess(orderCode, total_fee, orderName, orderName);

            return RespUtil.success(resultPay);

        } catch (Exception e) {
            e.printStackTrace();
        }

        return RespUtil.success(result);
    }

    /**
     * 阿里app支付调用
     *
     * @param orderCode
     * @param totalFee
     * @param title
     * @param content
     * @return
     */
    private Map<String, String> aliPayAccess(String orderCode, String totalFee, String title, String content) {
        Map<String, String> result = new HashMap<String, String>();

        String orderStr = aliPayAppAccess(orderCode, totalFee, title, content);
        result.put("payType", "app");
        result.put("order", orderStr);
        return result;
    }

    /**
     * 阿里app支付调用
     *
     * @param orderCode
     * @param totalFee
     * @param title
     * @param content
     * @return
     */
    private String aliPayAppAccess(String orderCode, String totalFee, String title, String content) {
        //实例化客户端
        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", AliMiniConfig.ALI_MINI_APP_ID, AliMiniConfig.ALI_PRIVATE_KEY, "json", "utf-8", AliMiniConfig.ALI_PUBLIC_KEY, "RSA2");
        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        //SDK已经封装掉了公共参数，这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        model.setBody(content);
        model.setSubject(title);
        model.setOutTradeNo(orderCode);
        model.setTimeoutExpress("30m");
        model.setTotalAmount(totalFee);
        model.setProductCode("QUICK_MSECURITY_PAY");
        request.setBizModel(model);
        request.setNotifyUrl("https://ejiakanghu.com.cn/ali_pay/callback");
        try {
            //这里和普通的接口调用不同，使用的是sdkExecute
            AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
            return response.getBody();//就是orderString 可以直接给客户端请求，无需再做处理。
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 当面付阿里调用
     *
     * @param orderCode
     * @param totalFee
     * @param title
     * @return
     */
    private String aliPayFaceAccess(String orderCode, String totalFee, String title, Object buyerId) {
        if (buyerId == null) {
            logger.error("ali face access err {},{}", orderCode, title);
            return null;
        }
        //实例化客户端
        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", AliMiniConfig.ALI_MINI_APP_ID, AliMiniConfig.ALI_PRIVATE_KEY, "json", "utf-8", AliMiniConfig.ALI_PUBLIC_KEY, "RSA2");
        //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称：alipay.trade.create.
        AlipayTradeCreateRequest request = new AlipayTradeCreateRequest();
        request.setNotifyUrl("https://ejiakanghu.com.cn/ali_pay/callback");
        //SDK已经封装掉了公共参数，这里只需要传入业务参数。
        request.setBizContent("{" +
                "\"out_trade_no\":\"" + orderCode + "\"," +
                "\"total_amount\":" + totalFee + "," +
                "\"subject\":\"" + title + "\"," +
                "\"buyer_id\":\"" + buyerId + "\"" +
                "}");
        try {
            //使用的是execute
            AlipayTradeCreateResponse response = alipayClient.execute(request);
            String trade_no = response.getTradeNo();//获取返回的tradeNO。
            return trade_no;
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 微信付款成功或失败回调接口
     * <p>
     * 1. 检测当前订单是否是付款状态;
     * 2. 设置订单付款成功状态相关信息;
     * 3. 响应微信商户平台.
     *
     * @param request  请求内容
     * @param response 响应内容
     * @return 操作结果
     */
    @Transactional
    public Object payNotify(HttpServletRequest request, HttpServletResponse response) {
        Map requestParams = request.getParameterMap();
        logger.debug("alicallback,{}", JacksonUtil.gson.toJson(requestParams));
        Map<String, String> params = new HashMap<String, String>();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }
        boolean signVerified = false;
        try {
            String charset = params.get("charset");
            if (StringUtils.isBlank(charset)) {
                charset = "utf-8";
            }
            signVerified = AlipaySignature.rsaCheckV1(params, AliMiniConfig.ALI_PUBLIC_KEY, charset, "RSA2"); //调用SDK验证签名
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        if (!signVerified) {
            return RespUtil.fail();
        }
        logger.info("处理支付宝支付平台的订单支付");

        // 验签成功后
        //按照支付结果异步通知中的描述，对支付结果中的业务内容进行1\2\3\4二次校验，校验成功后在response中返回success，校验失败返回failure
        String orderSn = params.get("out_trade_no");
        String payId = params.get("trade_no");
        String totalFee = params.get("total_amount");

        LitemallOrder order = orderService.findBySn(orderSn);
        if (order == null) {
            return WxPayNotifyResponse.fail("订单不存在 sn=" + orderSn);
        }

        // 检查这个订单是否已经处理过
        if (OrderUtil.hasPayed(order)) {
            return RespUtil.success("订单已经处理成功!");
        }

        // 检查支付订单金额
        if (!totalFee.equals(order.getActualPrice().toString())) {
            return WxPayNotifyResponse.fail(order.getOrderSn() + " : 支付金额不符合 totalFee=" + totalFee);
        }

        order.setPayId(payId);
        order.setPayTime(LocalDateTime.now());
        order.setOrderStatus(OrderUtil.STATUS_PAY);
        if (orderService.updateWithOptimisticLocker(order) == 0) {
            return WxPayNotifyResponse.fail("更新数据已失效");
        }

        //  支付成功，有团购信息，更新团购信息
        LitemallGroupon groupon = grouponService.queryByOrderId(order.getId());
        if (groupon != null) {
            LitemallGrouponRules grouponRules = grouponRulesService.findById(groupon.getRulesId());

            //仅当发起者才创建分享图片
            if (groupon.getGrouponId() == 0) {
                String url = qCodeService.createGrouponShareImage(grouponRules.getGoodsName(), grouponRules.getPicUrl(), groupon);
                groupon.setShareUrl(url);
            }
            groupon.setStatus(GrouponConstant.STATUS_ON);
            if (grouponService.updateById(groupon) == 0) {
                return WxPayNotifyResponse.fail("更新数据已失效");
            }


            List<LitemallGroupon> grouponList = grouponService.queryJoinRecord(groupon.getGrouponId());
            if (groupon.getGrouponId() != 0 && (grouponList.size() >= grouponRules.getDiscountMember() - 1)) {
                for (LitemallGroupon grouponActivity : grouponList) {
                    grouponActivity.setStatus(GrouponConstant.STATUS_SUCCEED);
                    grouponService.updateById(grouponActivity);
                }

                LitemallGroupon grouponSource = grouponService.queryById(groupon.getGrouponId());
                grouponSource.setStatus(GrouponConstant.STATUS_SUCCEED);
                grouponService.updateById(grouponSource);
            }
        }

        //TODO 发送邮件和短信通知，这里采用异步发送
        // 订单支付成功以后，会发送短信给用户，以及发送邮件给管理员
        notifyService.notifyMail("新订单通知", order.toString());
        // 这里微信的短信平台对参数长度有限制，所以将订单号只截取后6位
        notifyService.notifySmsTemplateSync(order.getMobile(), NotifyType.PAY_SUCCEED, new String[]{orderSn.substring(8, 14)});

        // 请依据自己的模版消息配置更改参数
        String[] parms = new String[]{
                order.getOrderSn(),
                order.getOrderPrice().toString(),
                DateTimeUtil.getDateTimeDisplayString(order.getAddTime()),
                order.getConsignee(),
                order.getMobile(),
                order.getAddress()
        };

        // 取消订单超时未支付任务
//        taskService.removeTask(new OrderUnpaidTask(order.getId()));

        return WxPayNotifyResponse.success("处理成功!");
    }


}
